package es.uab.es2.TimeTracker.nucli;

import java.util.*;

public class Attributes extends LinkedList {

    public Attributes() {
	super();
    }

    public Attributes(String attr) throws IllegalArgumentException {
	super();
	setAttributes(attr);
    }

    public Attributes(Attribute[] attrs) {
	super();
	for (int i = 0; i < attrs.length; i++) {
	    add(attrs[i]);
	}
    }

    public Attributes(Attribute attr) {
	super();
	add(attr);
    }

    /**
       * Set the value of attributes.
       * @param str  String with HTML attributes like:
       * border="0" cellpadding="0" cellspacing="0"
       */

    public void setAttributes(String str) throws IllegalArgumentException {
	Attribute attribute = new Attribute();	
	final int START = 0;
	// final int EOL = 1;
	final int ERR = -1;
	final int Attr = 2;
	final int Val0 = 3;
	final int Val1 = 4;
	final int Value = 5;
	final int QVal = 6;
	// finite state machine for parsing
	int state = START;
	int prev = -1; // debug
	int i = 0;
	StringBuffer token = new StringBuffer();

	while ((i <= str.length()) && (state != ERR)) {
	    char chr;
	    if (i < str.length())
		chr = str.charAt(i);
	    else
		chr = ' ';
	    i++;
	    prev = state;
	    switch(state) {
	    case START:
		switch(chr) {
		case ' ': break;
		case '"': case '=': 
		    state = ERR; break;
		default: token.append(chr); state = Attr;
		}
		break;
	    case Attr:
		switch(chr) {
		case ' ': 
		    attribute = new Attribute(token.toString());
		    state = Val0;
		    break;
		case '=': 		    
		  attribute = new Attribute(token.toString());
		  state = Val1; 
		  break;
		case '"':
		    state = ERR; break;
		default: token.append(chr);
		}
		break;
	    case Val0:
	        switch(chr) {
	            case '=': state = Val1; break;
	            case ' ': break;
	            default: 
		      this.add(attribute);
		      token = new StringBuffer();
		      token.append(chr);
		      state = Attr;
	        }
		break;
	    case Val1:
	        token = new StringBuffer();
	        switch(chr) {
	        case '"': state = QVal; break;
	        case '=': state = ERR; break;
	        case ' ': break;
	        default: 
		  token.append(chr);
		  state = Value;
		  break;
		}
		break;
	    case Value:
		switch(chr) {
		case ' ':
		    attribute.setValue(token.toString());
		    this.add(attribute);
		    token = new StringBuffer();
		    state = START;
		    break;
		case '=': state = ERR; break;
		default: token.append(chr);
		}
		break;
	    case QVal:
		switch(chr) {
		case '"':
		    attribute.setValue(token.toString());
		    this.add(attribute);
		    token = new StringBuffer();
		    state = START;
		    break;
		default: token.append(chr);
		}
		break;
	    }
	}
	if ((i <= str.length()) || (state == ERR)) {
	    System.err.println("Parse error:");
	    System.err.println(str);
	    for (int j = 0; j < i; j++)
		System.err.print(' ');
	    System.err.println('^');
	    throw new IllegalArgumentException("Parse error in state " + 
					       Integer.toString(prev));
	}
    }
	
    public String toString() {
	StringBuffer out = new StringBuffer(" ");
	ListIterator iterator = this.listIterator();
	while (iterator.hasNext()) {
	    out.append(iterator.next().toString());
	    out.append(' ');
	}
	out.deleteCharAt(out.length() - 1);
	return out.toString();
    }
}
